積み上げたコミットを整理したくなった時に覚えておきたい或いは思い出したいgit rebaseの手続きを試してみた
PullRequestを出す時、作業用ブランチでコミットを細かく刻みすぎている場合はgit rebase
にてある程度のまとまりにしつつ、合わせてコメントも変更したほうがレビューもし易くなります。ただ、rebaseする時に悩ましいのがコミット範囲指定です。HEAD~x
のxの指定ですね。
比較的大きめの範囲を指定した上でsquashの対象を絞り込めばよいのですが、大きめの範囲を求めるにもコミット内容の遡りは変わらず必要になります。そしてコミットが大きくなるほどスクロール量も増えます。差分を確認するのも一苦労です。
以下のようなコミットをまとめるのならまだしも、実際は検討すべき項目が数多く上がります。
% git log commit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Author: haoyayoi <xxxxxxxxxxxxxxx@gmail.com> Date: Mon Jun 14 14:25:12 2021 +0900 fix typo commit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Author: haoyayoi <xxxxxxxxxxxxxxx@gmail.com> Date: Mon Jun 14 14:23:42 2021 +0900 fix typo commit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Author: haoyayoi <xxxxxxxxxxxxxxx@gmail.com> Date: Mon Jun 14 14:21:22 2021 +0900 fix typo
より快適にrebaseする方法は幾つかあります。「どんな状況でも多分多少はマシになる」というものを幾つかピックアップして試してみました。
GitHub Desktop
squash限定になりますが、これ以上気楽にrebaseできるクライアントはないと思います。
rebase対象にするコミットを範囲選択して右クリック。
squashを選択して実行するのみです。
tig
Terminalだけで済ませたい場合はGitよりもTigの方がよいでしょう。
% brew install tig
Rebase操作を手軽にするため、.tigrc
に設定を追加しておきます。
% vim ~/.tigrc bind main R !git rebase -i %(commit) bind diff R !git rebase -i %(commit)
R
キー一つでRebase操作が開始可能になりました。
Tigを起動してEnter
キーを押してコミットログを確認しつつ、対象にしたい最も古いコミットログ上でR
を押します。GitHub Desktopと違って、squashかfixupのいずれかを個別に指定します。
- squash
- コミットそれぞれのコメントを纏められる
- fixup
- 対象コミットからコメントを排除した上で直前コミットへの差分統合を行う
所謂fix typoで無い限りはsquash
を選択した上でコメントを再編集したほうがレビュー時に意図が分かりやすくなります。
これをやっておきたいのならrebase
普段の利用頻度が少なければ何が出来るのかも把握しづらいものです。「こんなことをやっておきたい」という時に「それrebaseでできるよ」というものを一部ピックアップしてみました。
- 作業ブランチ内で既に積み上げたコミットのコメントを変更する
- 一度に複数追加したファイルを個別のコミットに分けて追加し直したい
- コミットの順番を入れ替えたい
作業ブランチ内で既に積み上げたコミットのコメントを変更する
Tigを起動し、編集したいコミットよりも下のコミットにフォーカスを当ててからR
を押します。(セキュリティ対策…のコミットが対象)
該当コミットのpick
をedit
に変更して保存します。
Before:
pick zzzzzzzz セキュリティ対策としてDeploy用RoleとCfn用Roleを切り分ける
After:
edit zzzzzzzz セキュリティ対策としてDeploy用RoleとCfn用Roleを切り分ける
すると以下の表示に切り替わります。どうしたらよいものかと慌てそうですが、先ずは指示通りEnterを押します。
You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue Press Enter to continue
次にq
を押してTigを閉じます。そして、ターミナル上に残っている指示に従います。
先ずはコメントの修正。
% git commit --amend
続いてrebase作業の続きです。
% git rebase --continue
これで既に積んでいたコミットのコメント修正が完了しました。複数コミットのコメントを変更したい場合は、同じくrebaseにてそれぞれをeditと変更します。
以下は2つのコミットに対して、コメントを変更してrebaseの継続、をコミット毎に行う例です。
# 最初のeditコミット % git commit --amend # 次のコミットへ移行 % git rebase --continue # 次のeditコミット % git commit --amend # 完了 % git rebase --continue
一度に複数追加したファイルを個別のコミットに分けて追加し直したい
これもrebaseにて対象コミットをpick
からedit
に変更して保存し、Tigを閉じるまでは同じです。コミットし直すためgit reset HEAD^
にてstageから纏めて下ろします。
% git reset HEAD^ Unstaged changes after reset: M XXXXX M XXXXX
その後、個別にコミットしていきます。コミットが終わったらgit rebase --continue
を実行します。stageから下ろしたファイルの中にコミット漏れがあった場合、その後のコミットと衝突する場合があるので注意しましょう。
やり直したい場合は以下のコマンドにてrebase操作をなかったことにできます。
% git rebase --abort
コミットの順番を入れ替えたい
rebase操作時に、コミットの順番を書き換えて保存します。
Before:
pick xxxxxxxx fix workflow pick yyyyyyyy ワークフロー共通化に伴う調整 pick zzzzzzzz bootstrapを入れないとアカウントが切り替わらない
After:
pick zzzzzzzz bootstrapを入れないとアカウントが切り替わらない pick xxxxxxxx fix workflow pick yyyyyyyy ワークフロー共通化に伴う調整
新規ファイルの追加順調整に用いる程度にしておいた方が無難です。
あとがき
コミットは作業ブランチのユニットテストでの修正やGitHub Actions等でのCICD動作検証で細かく多量に積みがちです。一通り動作し終えたら、細かく積んだコミットを見直して一つの塊にし、修正の意図が読み取れやすくしておきましょう。
ただし、書き換えた後に差分に整合性がとれなくなるケースや、他の作業ブランチのマージコミット等のハッシュが弄れないコミットが含まれる場合等、解決が困難になるケースでの利用は避けましょう。